﻿namespace IconPatcher
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;

    using IconPatcher.Annotations;

    [UsedImplicitly]
    public class ExtractIcons : BetterConsoleCommand
    {
        private const VisualStudioVersion Version = VisualStudioVersion.VS2010;

        private string InstallPath;
        private string ImageFolder;

        private string[] Languages;

        public ExtractIcons()
        {
            IsCommand("extract", "Extracts the current known icons from Visual Studio 2010.");
        }

        public override int Run(string[] remainingArguments)
        {
            if (!Program.Support2010)
            {
                ErrorMessage("You cannot run this command while in inject mode.");
                return 1;
            }

            if (!ForceVisualStudioToBeClosed("Extract Canceled"))
            {
                return 0;
            }

            var status = Helpers.GetInstallPath(Version, out InstallPath);
            if (status != 0)
            {
                return status;
            }

            ImageFolder = Path.Combine(Environment.CurrentDirectory, "Images");
            if (!Directory.Exists(ImageFolder))
            {
                Directory.CreateDirectory(ImageFolder);
            }

            Languages = GetLanguagess(Version);

            Helpers.DllList.ForEach(ExtractFromDll);

            SuccessMessage("Extract Finished");

            return 0;
        }

        private void ExtractFromDll(DllInformation dll)
        {
            if (!dll.SupportsCulture)
            {
                ExtractFromDll("1033", dll);
                return;
            }

            foreach (var language in Languages)
            {
                ExtractFromDll(language, dll);
            }
        }

        private void ExtractFromDll(string language, DllInformation dll)
        {
            var sourceDll = Path.Combine(InstallPath, dll.ExpandedPath(language));
            if (!File.Exists(sourceDll))
            {
                LogMessage("File not found: {0}", sourceDll.Remove(InstallPath));
                return;
            }

            var library = NativeMethods.LoadLibraryEx(sourceDll, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
            if (library == IntPtr.Zero)
            {
                ErrorMessage("Error loading file {0}", sourceDll.Remove(InstallPath));
                ErrorMessage(Helpers.LastWin32ErrorMessage());
                return;
            }

            var outFile = string.Format("{0}.{1}.bmp", new FileInfo(sourceDll).Name, dll.ImageIdString);

            // there are a number of ways to load a bitmap object from the dll but the only
            // one which seems to work without causing VS to display semi-corrupt images in
            // some places is Bitmap.FromResource so I'm sticking with it
            using (var bitmap = Bitmap.FromResource(library, dll.ImageResourceIdString))
            {
                bitmap.Save(Path.Combine(ImageFolder, outFile), ImageFormat.Bmp);
            }

            if (!NativeMethods.FreeLibrary(library))
            {
                ErrorMessage(Helpers.LastWin32ErrorMessage());
            }
        }
    }
}